﻿using System;
using System.IO;
using Beaker.Specs;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenCube.IO.Specs.Builders;
using OpenCube.Model.Enums;
using OpenCube.Model.Primitives;
using OpenCube.Model.Specs.Builders;
using OpenCube.Nbt;
using OpenCube.Nbt.Mapping;
using OpenCube.Nbt.Specs.Builders;

namespace OpenCube.Model.Specs
{
	[TestClass]
	internal sealed class LevelDatMappingSpecs
		: SpecsFor<NbtMapper<LevelDat>, NbtMapperBuilder<LevelDat>>
	{
		[TestMethod]
		public void OriginalLevelDatShouldMapToLevelDatModel()
		{
			// open resource as stream
			Stream stream = new ResourceStreamBuilder()
				.NearType(GetType())
				.InFolder("Resources")
				.WithFilename("level.dat")
				.Build();

			// deserialize to dictionary
			NbtDeserializer deserializer = new NbtDeserializerBuilder().Build();
			var dictionary = (NbtDictionary)deserializer.Deserialize(stream)["Data"];

			// arrange
			var queryContainer = new QueryContainerStub();

			NbtMapperFactory mapperFactory = new NbtMapperFactoryBuilder()
				.WithQueryContainer(queryContainer)
				.Build();
			queryContainer.Register<INbtMapperFactory>(mapperFactory);

			BuildSubject
				.WithQueryContainer(queryContainer);

			// act - map dictionary to model
			LevelDat model = Subject.MapToModel(dictionary);

			// assert
			model.Version.Should().Be(19133);
			model.IsInitialized.Should().BeTrue();
			model.LevelName.Should().Be("Amazing");
			model.GeneratorType.Should().Be(GeneratorType.Default);
			model.GeneratorVersion.Should().Be(1);
			// model.GeneratorOptions.Should().Be("")
			model.RandomSeed.Should().Be(-1843795928307041502);
			model.MapFeatures.Should().BeTrue();
			model.LastPlayed.Should().Be(new DateTime(2014, 05, 19, 7, 43, 22, 732, DateTimeKind.Utc));
			model.AllowCommands.Should().BeFalse();
			model.IsHardcore.Should().BeFalse();
			model.GameType.Should().Be(GameType.Creative);
			model.Difficulty.Should().Be(Difficulty.Normal);
			model.RunningTime.Should().Be(new GameTimeSpan(59270430));
			model.TimeOfDay.Should().Be(new GameTimeSpan(60762955));
			model.SpawnLocation.Should().Be(new Coordinates3<int>(155, 64, 127));
			model.WorldBorder.Should().NotBeNull();
			model.WorldBorder.BorderSize.Should().Be(60000000d);
			model.WorldBorder.BorderSafeZone.Should().Be(5);
			model.WorldBorder.BorderWarningBlocks.Should().Be(5);
			model.WorldBorder.BorderWarningTime.Should().Be(15.Seconds());
			model.WorldBorder.BorderSizeLerpTarget.Should().Be(60000000);
			model.WorldBorder.BorderSizeLerpTime.Should().Be(0.Seconds());
			model.WorldBorder.BorderDamagePerBlock.Should().Be(0.2d);
			model.IsRaining.Should().BeFalse();
			model.RainTime.Ticks.Should().Be(30869);
			model.IsThundering.Should().BeFalse();
			model.ThunderTime.Ticks.Should().Be(59967);
			model.ClearWeatherTime.Ticks.Should().Be(0);
			model.GameRules.CommandBlockOutput.Should().BeTrue();
			model.GameRules.DoDaylightCycle.Should().BeTrue();
			model.GameRules.DoFireTick.Should().BeTrue();
			model.GameRules.DoMobLoot.Should().BeTrue();
			model.GameRules.DoMobSpawning.Should().BeTrue();
			model.GameRules.DoTileDrops.Should().BeTrue();
			model.GameRules.KeepInventory.Should().BeFalse();
			model.GameRules.LogAdminCommands.Should().BeTrue();
			model.GameRules.MobGriefing.Should().BeTrue();
			model.GameRules.NaturalRegeneration.Should().BeTrue();
			model.GameRules.RandomTickSpeed.Should().Be(3);
			model.GameRules.SendCommandFeedback.Should().BeTrue();
			model.GameRules.ShowDeathMessages.Should().BeTrue();
			model.Player.Position.Should().Be(new Coordinates3<double>(169.82978510127d, 72d, 133.015981542442d));
		}
	}
}
